import { Injectable, HttpException, HttpStatus, Inject, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SHA1 } from 'crypto-js';
import axios, { AxiosInstance, AxiosError } from 'axios';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';

interface WechatErrorResponse {
  errcode: number;
  errmsg: string;
}

interface WechatAccessTokenResponse extends WechatErrorResponse {
  access_token?: string;
  expires_in?: number;
}

interface WechatJsapiTicketResponse extends WechatErrorResponse {
  ticket?: string;
  expires_in?: number;
}

@Injectable()
export class WechatService implements OnModuleInit {
  private readonly appId: string;
  private readonly appSecret: string;
  private readonly ACCESS_TOKEN_KEY = 'wechat_access_token';
  private readonly JSAPI_TICKET_KEY = 'wechat_jsapi_ticket';
  private readonly CACHE_TTL = 7000; // 缓存时间，单位：秒
  private axiosInstance: AxiosInstance;

  constructor(
    private configService: ConfigService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
  ) {
    this.appId = this.configService.get('WECHAT_APP_ID');
    this.appSecret = this.configService.get('WECHAT_APP_SECRET');
  }

  onModuleInit() {
    // 创建配置了代理的 axios 实例
    const proxyHost = this.configService.get('HTTP_PROXY_HOST');
    const proxyPort = this.configService.get('HTTP_PROXY_PORT');

    const axiosConfig: any = {
      timeout: 10000, // 10 秒超时
    };

    if (proxyHost && proxyPort) {
      console.log(`🔧 使用代理: ${proxyHost}:${proxyPort}`);
      axiosConfig.proxy = {
        host: proxyHost,
        port: parseInt(proxyPort, 10),
      };
    } else {
      console.log('ℹ️ 未配置代理，使用直连模式');
    }

    this.axiosInstance = axios.create(axiosConfig);
  }

  private generateNonceStr(length = 16): string {
    const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let nonceStr = '';
    for (let i = 0; i < length; i++) {
      nonceStr += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return nonceStr;
  }

  private createTimestamp(): string {
    return Math.floor(Date.now() / 1000).toString();
  }

  private generateSignature(params: Record<string, string>): string {
    const keys = Object.keys(params).sort();
    const string = keys.map(key => `${key}=${params[key]}`).join('&');
    return SHA1(string).toString();
  }

  private async getAccessToken(): Promise<string> {
    try {
      // 尝试从缓存获取
      const cachedToken = await this.cacheManager.get<string>(this.ACCESS_TOKEN_KEY);
      if (cachedToken) {
        console.log('✅ 使用缓存的 access_token');
        console.log('🔍 当前缓存键:', this.ACCESS_TOKEN_KEY);
        return cachedToken;
      }

      console.log('🔄 正在从微信服务器获取新的 access_token...');
      const response = await this.axiosInstance.get<WechatAccessTokenResponse>('https://api.weixin.qq.com/cgi-bin/token', {
        params: {
          grant_type: 'client_credential',
          appid: this.appId,
          secret: this.appSecret,
        },
      });

      console.log('📡 微信服务器响应:', JSON.stringify(response.data, null, 2));

      if (response.data.access_token) {
        const token = response.data.access_token;
        // 存入缓存，明确指定 TTL
        await this.cacheManager.set(this.ACCESS_TOKEN_KEY, token, this.CACHE_TTL * 1000);
        console.log('💾 新的 access_token 已缓存，有效期', this.CACHE_TTL, '秒');
        console.log('🔍 缓存键:', this.ACCESS_TOKEN_KEY);
        console.log('🔍 缓存值:', token);
        return token;
      }

      console.error('❌ 获取 access_token 失败');
      console.error('❌ 错误详情:', {
        errcode: response.data.errcode,
        errmsg: response.data.errmsg,
        params: {
          appid: this.appId,
          secret: '***' // 出于安全考虑不显示完整的 secret
        }
      });

      throw new Error(`获取 access_token 失败：${response.data.errmsg || '未知错误'} (错误码: ${response.data.errcode || 'UNKNOWN'})`);
    } catch (error) {
      console.error('❌ 获取 access_token 失败');
      if (error instanceof Error) {
        console.error('❌ 错误信息:', error.message);
        if (axios.isAxiosError(error)) {
          console.error('❌ 服务器响应:', error.response?.data);
        }
        console.error('❌ 错误堆栈:', error.stack);
      } else {
        console.error('❌ 未知错误:', error);
      }
      throw new HttpException('获取 access_token 失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  private async getJsapiTicket(): Promise<string> {
    try {
      // 尝试从缓存获取
      const cachedTicket = await this.cacheManager.get<string>(this.JSAPI_TICKET_KEY);
      if (cachedTicket) {
        console.log('✅ 使用缓存的 jsapi_ticket');
        console.log('🔍 当前缓存键:', this.JSAPI_TICKET_KEY);
        return cachedTicket;
      }

      console.log('🔄 正在从微信服务器获取新的 jsapi_ticket...');
      const accessToken = await this.getAccessToken();
      const response = await this.axiosInstance.get<WechatJsapiTicketResponse>('https://api.weixin.qq.com/cgi-bin/ticket/getticket', {
        params: {
          access_token: accessToken,
          type: 'jsapi',
        },
      });

      console.log('📡 微信服务器响应:', JSON.stringify(response.data, null, 2));

      if (response.data.ticket) {
        const ticket = response.data.ticket;
        // 存入缓存，明确指定 TTL
        await this.cacheManager.set(this.JSAPI_TICKET_KEY, ticket, this.CACHE_TTL * 1000);
        console.log('💾 新的 jsapi_ticket 已缓存，有效期', this.CACHE_TTL, '秒');
        console.log('🔍 缓存键:', this.JSAPI_TICKET_KEY);
        console.log('🔍 缓存值:', ticket);
        return ticket;
      }

      console.error('❌ 获取 jsapi_ticket 失败');
      console.error('❌ 错误详情:', {
        errcode: response.data.errcode,
        errmsg: response.data.errmsg,
        params: {
          access_token: '***', // 出于安全考虑不显示完整的 token
          type: 'jsapi'
        }
      });

      throw new Error(`获取 jsapi_ticket 失败：${response.data.errmsg || '未知错误'} (错误码: ${response.data.errcode || 'UNKNOWN'})`);
    } catch (error) {
      console.error('❌ 获取 jsapi_ticket 失败');
      if (error instanceof Error) {
        console.error('❌ 错误信息:', error.message);
        if (axios.isAxiosError(error)) {
          console.error('❌ 服务器响应:', error.response?.data);
        }
        console.error('❌ 错误堆栈:', error.stack);
      } else {
        console.error('❌ 未知错误:', error);
      }
      throw new HttpException('获取 jsapi_ticket 失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async getJssdkConfig(url: string) {
    try {
 
      console.log('📝 开始生成 JSSDK 配置...');
      const jsapiTicket = await this.getJsapiTicket();
      const nonceStr = this.generateNonceStr();
      const timestamp = this.createTimestamp();

      const params = {
        noncestr: nonceStr,
        jsapi_ticket: jsapiTicket,
        timestamp: timestamp,
        url: url,
      };

      const signature = this.generateSignature(params);
      console.log('✨ JSSDK 配置生成成功');

      return {
        appId: this.appId,
        timestamp,
        nonceStr,
        signature,
      };
    } catch (error) {
      console.error('❌ 获取微信 JSSDK 配置失败:', error instanceof Error ? error.message : error);
      throw error;
    }
  }
} 